---@class Xiangqi.GameLogic : Base.GameLogic
---@field public room Xiangqi.Room
local GameLogic = Fk.Base.GameLogic:subclass("Xiangqi.GameLogic")

local Xq = require "packages.chess-games.xiangqi"

function GameLogic:run()
  table.shuffle(self.room.players)
  self:adjustSeats()
  self:assignRole()

  self:initBoard()

  self:action()
end

function GameLogic:assignRole()
  local room = self.room
  room:setPlayerProperty(room.players[1], "role", "red")
  room:setPlayerProperty(room.players[2], "role", "black")
end

---@param board integer[][]?
function GameLogic:initBoard(board)
  local room = self.room
  if board then
    room.board = board
  end

  room:syncBoard()
end

function GameLogic:turn(count)
  local room = self.room
  local redMove, blackMove

  for _, player in ipairs(room.players) do
    local color = player.role
    local board = room.board

    local movable = {} ---@type [integer, integer, integer][]
    for y, arr in ipairs(board) do
      for x, id in ipairs(arr) do
        local piece = Xq:getPieceById(id)
        if piece and piece:getColor() == color and piece:canMove(board, x, y) then
          table.insert(movable, { id, x, y })
        end
      end
    end

    if #movable == 0 then
      if redMove then
        room:sendLog {
          type = "#XiangqiMoveHalf",
          arg = count,
          arg2 = redMove,
        }
      end

      room:gameOver(player.next.role)
      return
    end

    local tmp = table.random(movable)
    local pieceId, fromX, fromY = tmp[1], tmp[2], tmp[3]
    local movableXY = {} ---@type [integer, integer][]
    local piece = Xq:getPieceById(pieceId)
    for y, arr in ipairs(board) do
      for x, _ in ipairs(arr) do
        if piece:canMoveTo(board, fromX, fromY, x, y) and not piece:willBeChecked(board, fromX, fromY, x, y) then
          table.insert(movableXY, { x, y })
        end
      end
    end
    local xy = table.random(movableXY)
    local default = {
      pieceId = pieceId,
      fromX = fromX,
      fromY = fromY,
      x = xy[1],
      y = xy[2],
    }

    local req = Request:new(player, "Xiangqi.PlayChess")
    req:setData(player)
    req:setDefaultReply(player, default)
    -- req.timeout = 10000
    local result = req:getResult(player)

    local annotation = Xq:translateMovement(result.pieceId, board, result.fromX, result.fromY, result.x, result.y)
    if color == "red" then
      redMove = annotation
    else
      blackMove = annotation
    end
    room:movePieceTo(result.pieceId, result.fromX, result.fromY, result.x, result.y)
  end

  room:sendLog {
    type = "#XiangqiMove",
    arg = count,
    arg2 = redMove,
    arg3 = blackMove,
  }
end

function GameLogic:action()
  local room = self.room
  room:sendLog{
    type = "#XiangqiStart",
    arg = room.players[1]._splayer:getScreenName(),
    arg2 = room.players[2]._splayer:getScreenName(),
  }
  local i = 1
  while true do
    room:setBanner("RoundCount", i)
    self:turn(i)
    i = i + 1
  end
end

return GameLogic
